/*
 * Copyright (c) 2021，上海福宇龙汽车科技有限公司
 * All rights reserved.
 * 文件名称: app_ehbl_uart.c
 * 摘要:
 * 当前版本: V1.0.0 zw
 * Date: 2024-01-29
 * 历史版本: Vx.x.x，编写者/修改者，修改时间，修改内容（重大发布时，总结重点变更内容）
 */
#include <stdio.h>
#include <string.h>
#include "app_ehbl_uart.h"
#include "app_crc.h"
#include "rte.h"
#include "usart.h"
#include "lock_uart.h"
#include "nfc_ctrl.h"
#include "key.h"
#include "lock_loop.h"
static uint32_t bswap32(uint32_t data);
static uint16_t bswap16(uint16_t data);
static uart_transmit_un tx_info;
static uart_transmit_un rx_info;
static uart_recv_sta_st recv_st;

/*
 * 函数介绍:清接收buffer
 * 参数:
 * 返回值: {*}
 * 备注:
 */
static void app_uart_clr_buffer(void)
{
    recv_st.allow_recv_flag = 1;
    recv_st.recv_len = 0;
    memset(recv_st.data, 0, UART_RECV_LENGTH);
    recv_st.recv_complete = 0;
    recv_st.Processing_data = 0;
}

/*
 * 函数介绍: 串口4协议初始化
 * 参数:
 * 返回值: {*}
 * 备注:
 */
void Uart4_init(void)
{
    tx_info.sig.start = UART_FRAME_START;
    tx_info.sig.len = UART_RECV_LENGTH;
    tx_info.sig.single = UART_FILL;
    tx_info.sig.err = UART_FILL;
    tx_info.sig.res = UART_FILL;
    tx_info.sig.end = UART_FRAME_END;
    app_uart_clr_buffer();
}

/*
 * 函数介绍:接收串口发送过来的数据
 * 参数:
 *          recv_data：串口发送过来的数据
 * 返回值: {*}
 * 备注:放到串口接收回调中调用
 */
void app_uart_get_recvdata(uint8_t *recv_data, uint16_t len)
{
    uint8_t r_data;
    r_data = *recv_data;

    /*检查接收标志是否允许接收*/
    if (!(recv_st.allow_recv_flag))
    {
        return;
    }
    /*接收帧头*/
    if ((recv_st.recv_len == 0) && (r_data == (UART_FRAME_START & 0xff)))
    {
        recv_st.data[recv_st.recv_len] = r_data;
        recv_st.recv_len += 1;
    }
    else if (recv_st.recv_len > 0)
    {
        recv_st.data[(recv_st.recv_len)] = r_data;
        recv_st.recv_len += 1;
        /*判断接收到的数据长度和实际接收长度是否相同*/
        if (((recv_st.recv_len)) == recv_st.data[2])
        {
            recv_st.allow_recv_flag = 0;
            recv_st.recv_complete = 1;
        }
    }
    else
    {
        /*清接收数据buffer*/
        app_uart_clr_buffer();
    }
}

/**
 * 反转数组元素的顺序
 * 
 * 该函数用于将一个给定数组的元素顺序进行反转。
 * 
 * @param array 指向需要被反转的数组的指针。
 * @param size 数组的大小。
 * 
 * @note 该函数不适用于空数组或只包含一个元素的数组。
 */
void reverse_array(uint8_t *array, size_t size) {
    uint8_t temp; // 用于交换元素的临时变量
    
    // 反转数组元素的顺序，只遍历数组的一半即可
    for (size_t i = 0; i < size / 2; i++) {
        // 交换数组两端的元素
        temp = array[i];
        array[i] = array[size - 1 - i];
        array[size - 1 - i] = temp;
    }
}

/*
 * 函数介绍:将串口接收的数据进行处理
 * 参数:
 * 返回值: {*}
 * 备注:
 */
static void app_uart_reveive_proc(void)
{
    static uint8_t step = 0;
    uint32_t recv_crc = 0;
    uint32_t cal_crc;
    if (recv_st.recv_len > 0 && recv_st.recv_complete == 1)
    {
        if (step == 0)
        {
            /*判断帧头是否为0x68FE*/
            if ((recv_st.data[0] + (recv_st.data[1] << 8)) == UART_FRAME_START)
            {
                step = 1;
            }
            else
            {
                app_uart_clr_buffer();
                step = 0;
                return;
            }
        }
        else if (step == 1)
        {
            /*获取接收到的crc数据*/
            recv_crc = (recv_st.data[recv_st.recv_len - 5] << 24) + (recv_st.data[recv_st.recv_len - 4] << 16) + (recv_st.data[recv_st.recv_len - 3] << 8) + (recv_st.data[recv_st.recv_len - 2] << 0);
            cal_crc = calcCRC32(&recv_st.data[2], 10);
            // cal_crc = recv_crc;
            /*计算得到的CRC与获取到的crc做比较*/
            if (recv_crc == cal_crc)
            {
                step = 2;
            }
            else
            {
                app_uart_clr_buffer();
                return;
            }
        }
        else if (step == 2)
        {
            /*判断接收到的数据尾是否为0xFC*/
            if (recv_st.data[recv_st.recv_len - 1] == UART_FRAME_END)
            {
                memcpy(rx_info.data, recv_st.data, UART_RECV_LENGTH);
                rx_info.sig.cmd = bswap16(rx_info.sig.cmd);
                reverse_array(rx_info.sig.pdata,4);
                recv_st.Processing_data = 1;/*数据处理完毕*/
                step = 0;
            }
            else
            {
                app_uart_clr_buffer();
                step = 0;
            }
        }
        else
        {
            step = 0;
        }
    }
}

/*
 * 函数介绍:
 * 参数:
 * 返回值: {*}
 * 备注:
 */
static void app_uart_cmd_event_proc()
{
    /*检查接收到的cmd是否存在，如果存在则执行该cmd对应的回调函数*/
    //if (rx_info.sig.cmd == tx_info.sig.cmd && recv_st.recv_complete == 1)
    if(1 == recv_st.Processing_data)
    {
        /*调用不同产品的回调函数*/
        if (STEERING_LOCK == rt_Curr_produ()) /*调用方向锁回调*/
        {
                Ehbl_uart_cbk(rx_info.sig.cmd, rx_info.sig.pdata);
                lock_loop_uartcb(rx_info.sig.cmd, rx_info.sig.pdata); 
        }
        else if (CONTROLLER == rt_Curr_produ()) /*调用控制器回调*/
        {
            NFCCTRL_uart_cbk(rx_info.sig.cmd, rx_info.sig.pdata);
        }
        memset(rx_info.data, 0, 17);
        app_uart_clr_buffer();
    }
}

static uint32_t bswap32(uint32_t data)
{
    return ((((data) & 0xff000000) >> 24) | (((data) & 0x00ff0000) >> 8) | (((data) & 0x0000ff00) << 8) | (((data) & 0x000000ff) << 24));
}

static uint16_t bswap16(uint16_t data)
{
    return ((((data) & 0xff00) >> 8) | (((data) & 0x00ff) << 8));
}

/*
 * 函数介绍: 串口4发送函数
 * 参数:
 * 返回值: {*}
 * 备注:
 */
void Uart4_send(uint16_t cmd, uint32_t pdata)
{
    uint32_t crc;
    cmd = bswap16(cmd);
    tx_info.sig.cmd = cmd;
    // 将uint32_t值分解为字节并存储在数组中
    tx_info.sig.pdata[0] = (pdata >> 24) & 0xFF; // 最高位字节
    tx_info.sig.pdata[1] = (pdata >> 16) & 0xFF; // 次高位字节
    tx_info.sig.pdata[2] = (pdata >> 8) & 0xFF;  // 次低位字节
    tx_info.sig.pdata[3] = pdata & 0xFF;         // 最低位字节
    /*采用crc32算法计算出的校验位，计算起始位到crc之间的数据，不包含起始位和crc*/
    crc = calcCRC32(&tx_info.data[2], 10);
    crc = bswap32(crc);
    tx_info.sig.crc = crc;
    // 检查HAL_UART_Transmit的返回值，以处理发送错误
    if (HAL_UART_Transmit(&huart4, tx_info.data, UART_RECV_LENGTH, 0xFFFF) != HAL_OK)
    {
        // 处理发送错误的逻辑，例如重试或记录错误日志
        // 注意：这里需要根据具体的HAL库错误处理机制来编写
    }
}

/*
 * 函数介绍:应用串口主入口
 * 参数:
 * 返回值: {*}
 * 备注:
 */
void app_uart_main(void)
{
    /*接收数据处理*/
    app_uart_reveive_proc();
    /*判断是否是存在的cmd*/
    app_uart_cmd_event_proc();
}
